import asyncio
from asyncio import Task
import time
import requests
import hmac
import hashlib
from urllib.parse import urlencode
from typing import List

from common.const import BaseConstant
from util.log import Log



class BinanceAPI:
    def __init__(self):
        self.api_url = BaseConstant.BASE_URL_API
        self.api_public_url = BaseConstant.BASE_URL_PUBLIC
        self.api_key = BaseConstant.API_KEY
        self.secret_key = BaseConstant.SECRET_KEY
        self.recv_window = BaseConstant.RECV_WINDOW
        self.taskList: List[Task] = []
        self.proxy_servers = {
            'https': BaseConstant.PROXY,
        }

    def _get_order(self, symbol):
        '''
        :param symbol:币种类型。如：BTCUSDT、ETHUSDT
        :return:
        '''
        params = {}
        params["symbol"] = symbol
        # 接收窗口
        params["recvWindow"] = self.recv_window
        return params

    def _order(self, symbol, quantity, side, price=None):
        '''
        :param symbol:币种类型。如：BTCUSDT、ETHUSDT
        :param quantity: 购买量
        :param side: 订单方向，买还是卖
        :param price: 价格
        :return:
        '''
        params = {}

        if price is not None:
            params["type"] = "LIMIT"
            params["price"] = "{:.8f}".format(price)
            params["timeInForce"] = "GTC"
        else:
            params["type"] = "MARKET"

        params["symbol"] = symbol
        params["side"] = side
        params["quantity"] = '%.8f' % quantity
        # 接收窗口
        params["recvWindow"] = self.recv_window

        return params

    # 构造签名
    def _sign(self, params: dict = {}):
        data = params.copy()
        # 时间戳
        ts = int(1000 * time.time())
        data.update({"timestamp": ts})
        # 参数的 content-type 需要为 application/x-www-form-urlencoded
        h = urlencode(data)
        # 使用 self.secret_key 加密参数 data，用来构造 signature
        b = bytearray()
        b.extend(self.secret_key.encode())
        signature = hmac.new(b, msg=h.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
        # 赋值 signature
        data.update({"signature": signature})
        return data

    # GET 请求
    def _get(self, path, params: dict = {}):
        query = self._sign(params)
        Log.info('query', query)
        header = {"X-MBX-APIKEY": self.api_key}
        return requests.get(url=path, headers=header, params=query, proxies=self.proxy_servers, timeout=20).json()

    # POST 请求
    def _post(self, path, params: dict = {}):
        # 使用 params 构造 signature，并返回新的 params
        query = urlencode(self._sign(params))
        Log.info('query', query)
        # header 需要 api_key
        header = {"X-MBX-APIKEY": self.api_key}
        return requests.post(url=path, headers=header, data=query, timeout=20).json()

    # 接口：下单
    def buy(self, symbol, quantity = None, price = None):
        path = f"{self.api_url}/api/v3/order/test"
        params = self._order(symbol, quantity, "BUY", price)
        return self._post(path, params)

    # 接口：获取订单
    def getOrder(self, symbol):
        path = f"{self.api_url}/api/v3/openOrders"
        params = self._get_order(symbol)
        return self._get(path, params)

    '''
    买入任务
    '''
    async def task(self):
        # self.buy('BTCUSDT')
        while True:
            Log.debug('正在运行 API')
            # # 买入策略
            # flag = True

            # # 当前可以买入
            # if flag:
            #     self.buy()
            # else:
            #     await asyncio.sleep(60)

            # res = await self.getOrder('BTCUSDT')
            # Log.debug('res', res)

            await asyncio.sleep(10)

    '''
    启动任务
    '''
    async def run(self):
        if len(self.taskList) == 0:
            task = asyncio.create_task(self.task())
            self.taskList.append(task)  # 将任务添加到全局任务列表
            return 0
        else:
            return len(self.taskList)
        
    '''
    停止任务
    '''
    async def stop(self):
        if len(self.taskList) > 0:
            for task in self.taskList:
                Log.info("Stopping the task.")
                task.cancel()  # 请求取消任务

                try:
                    await task  # 等待任务完成（被取消）
                except asyncio.CancelledError:
                    Log.info("Stopping the task successfully.")

            self.taskList.clear()

binanceAPI = BinanceAPI()